package org.zzz.hepotaiya.executor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.log4j.Logger;
import org.zzz.hepotaiya.beans.BatchInfo;
import org.zzz.hepotaiya.beans.BatchResult;
import org.zzz.hepotaiya.callable.CallableImpl;
import org.zzz.hepotaiya.enums.ResultType;
import org.zzz.hepotaiya.util.ResourceUtil;

public class CallableExecutor extends AbstractExecutor implements BatchExecutor {

	private static final Logger logger = Logger.getLogger(CallableExecutor.class);

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.zzz.hepotaiya.executor.BatchExecutor#doExecute(java.lang.String)
	 */
	public List<BatchResult> doExecute(String batchRootPackage) throws Exception {
		super.setUp();
		// バッチ読み込み
		Map<Integer, List<BatchInfo>> map = this.batchLoader.load(batchRootPackage, super.getConfigList());

		if (logger.isDebugEnabled()) {
			logger.debug(ResourceUtil.getString("executor.log.loaded"));
		}

		// フェーズ毎にバッチリスト取得
		for (int phase = 0; phase <= map.size(); phase++) {
			List<BatchInfo> list = map.get(phase);
			if (list == null) {
				continue;
			}
			if (logger.isDebugEnabled()) {
				logger.debug(ResourceUtil.getString("executor.log.phase.start", phase));
			}

			// 実行
			List<Future<BatchInfo>> futures = this.call(list);
			// 結果集計
			this.addResult(futures, phase);
			if (super.isError) {
				return super.resultList;
			}
			if (logger.isDebugEnabled()) {
				logger.debug(ResourceUtil.getString("executor.log.phase.end", phase));
			}
		}
		return super.resultList;
	}

	/**
	 * 非同期実行を行います。
	 * 
	 * @param バッチ情報リスト
	 * @return 実行結果リスト
	 * @throws Exception
	 */
	List<Future<BatchInfo>> call(List<BatchInfo> list) throws Exception {
		ExecutorService ex = Executors.newCachedThreadPool();
		List<Future<BatchInfo>> futureList = new ArrayList<Future<BatchInfo>>();
		try {
			for (BatchInfo info : list) {
				if (logger.isDebugEnabled()) {
					logger.debug(ResourceUtil.getString("executor.log.call", info.getBatchName()));
				}
				CallableImpl callable = new CallableImpl();
				callable.setSkipCause(super.checkDepency(info.getDependencies()));
				callable.setBatchInfo(info);

				Future<BatchInfo> f = ex.submit(callable);
				futureList.add(f);
			}
		} finally {
			ex.shutdown();
		}
		return futureList;
	}

	/**
	 * 結果格納を行います
	 * 
	 * @param 結果リスト
	 * @param フェーズ
	 * @throws Exception
	 */
	protected void addResult(List<Future<BatchInfo>> futureList, int phase)
			throws Exception {
		for (int n = 0; n < futureList.size(); n++) {
			BatchInfo result = futureList.get(n).get();
			if (result.getResultType() == ResultType.FAILURE && result.isErrorStop()) {
				super.isError = true;
			}
			boolean isSuccess = (result.getResultType() == ResultType.SUCCESS);
			super.resultMap.put(result.getBatchName(), isSuccess);
			super.resultList.add(result);
		}
	}

}
